/* Copyright 2008 Bas van den Berg
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "Respawner.h"

#include "Global.h"
#include "TaskQueue.h"
#include "myassert.h"

#include "World.h"
#include "Room.h"
#include "MudItem.h"
#include "MudContainer.h"
#include "MudCreature.h"
#include "MudPlayer.h"
#include "ItemDb.h"

using namespace Chronos;
using namespace std;

namespace Chronos {

class RespawnTask : public Task {
public:
    RespawnTask(Respawner* respawner_) : respawner(respawner_) {}
    virtual ~RespawnTask() {
        if (respawner) delete respawner;
    }
    virtual unsigned int run() {
        respawner->spawn();
        respawner = 0;
        return 0;
    }
private:
    Respawner* respawner;

    RespawnTask(const RespawnTask&);
    RespawnTask& operator= (const RespawnTask&);
};

}


Respawner::Respawner(unsigned int delay_)
    : delay(delay_)
{
    ASSERT_NOT_EQUAL(0, delay);
}

bool Respawner::handleObjectEvent(MudObject&, MudObjectEvent event) {
    if (event == OBJECT_DESTRUCTION) {
        delete this;
        return false;
    }
    if (event == MUDITEM_PICKUP || event == MUDMOBILE_DEATH) {
        Global<TaskQueue>()->addTask(new RespawnTask(this), delay);
        return false;
    }
    return true;
}


CreatureRespawner::CreatureRespawner(CreatureFactory* factory_, Room* room_, unsigned int delay_, const string& message_)
    : Respawner(delay_)
    , factory(factory_)
    , room(room_)
    , message(message_)
{
    CreatureRespawner::spawn();
}

void CreatureRespawner::spawn() {
    MudCreature& newCreature = factory->create();
    newCreature.addListener(*this);
    newCreature.addListener(Global<World>()->getKills());
    room->addObject(&newCreature);
    if (message != "") room->showText(message);
    if (newCreature.isAggro()) {
        MudPlayer* player = room->getFirstPlayer();
        if (player) newCreature.addTarget(*player);
    }
}


ItemRespawner::ItemRespawner(ItemFactory* factory_, Room* room_, unsigned int delay_, const string& message_)
    : Respawner(delay_)
    , factory(factory_)
    , room(room_)
    , message(message_)
{
    ItemRespawner::spawn();
}

void ItemRespawner::spawn() {
    MudItem& newItem = factory->create();
    newItem.addListener(*this);
    room->addObject(&newItem);
    if (message != "") room->showText(message);
}


ItemContainerRespawner::ItemContainerRespawner(ItemFactory* factory_, MudContainer* container_, unsigned int delay_)
    : Respawner(delay_)
    , factory(factory_)
    , container(container_)
{
    ItemContainerRespawner::spawn();
}

void ItemContainerRespawner::spawn() {
    MudItem& newItem = factory->create();
    newItem.addListener(*this);
    container->addItem(&newItem);
}

